package de.pharmacontrol.rfcserver.handler;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.sap.conn.jco.AbapClassException;
import com.sap.conn.jco.AbapException;
import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.server.JCoServerContext;

import de.pharmacontrol.pilot.entities.AI;
import de.pharmacontrol.pilot.entities.Line;
import de.pharmacontrol.pilot.entities.LineFormat;
import de.pharmacontrol.pilot.entities.Order;
import de.pharmacontrol.pilot.entities.OrderData;
import de.pharmacontrol.psa.beans.interfaces.AiService;
import de.pharmacontrol.psa.beans.interfaces.LineFormatService;
import de.pharmacontrol.psa.beans.interfaces.LineService;
import de.pharmacontrol.psa.beans.interfaces.LoggerService;
import de.pharmacontrol.psa.beans.interfaces.OrderService;

@Stateless
public class CreateOrderFunctionHandler extends FunctionHandler {

	
	@EJB
	LoggerService logger;

	@EJB
	OrderService orderBean;

	@EJB
	LineService lineBean;

	@EJB
	LineFormatService lineFormatBean;
	
	@EJB
	AiService aiBean;

	public final int CREATE_SUCCEEDED = 1;
	public final int CREATE_FAILED = 2;

	/**
	 * <Z_PPFM_PCE_ORDER_CREATE> <INPUT> <I_ORDER_CREATE>
	 * <ODERNR>000001001771</ODERNR> <ACTION>1</ACTION>
	 * <RESSOURCE>ZA_LIN1</RESSOURCE> <LAYOUT>TEST_PCE</LAYOUT>
	 * <MATNR>000000000000101701</MATNR> <MAKTX>HALLO PCE</MAKTX>
	 * <CHARG>123456</CHARG> <HSDAT>01.01.2011</HSDAT> <VFDAT>01.01.2013</VFDAT>
	 * <HSDAT_PRINT>01/2011</HSDAT_PRINT> <VFDAT_PRINT>01/2013</VFDAT_PRINT>
	 * <CHARGE_PRINT>HURRA</CHARGE_PRINT> <DRUCK_INFO1>24,57 EURO</DRUCK_INFO1>
	 * <DRUCK_INFO2>WARUM</DRUCK_INFO2> <DRUCK_INFO3>NICHT</DRUCK_INFO3>
	 * <CIP></CIP> <GS1_BATCH></GS1_BATCH> <GS1_HSDAT></GS1_HSDAT>
	 * <GS1_VFDAT></GS1_VFDAT> </I_ORDER_CREATE> </INPUT> <OUTPUT>
	 * <E_RETURNCODE></E_RETURNCODE> </OUTPUT> </Z_PPFM_PCE_ORDER_CREATE>
	 */
	@Override
	public void handleRequest(JCoServerContext serverCtx, JCoFunction function) throws AbapException, AbapClassException {

		final String xml = function.toXML();
		if (xml == null || xml.isEmpty()) {
			setReturnCode(function, CREATE_FAILED);
			return;
		}

		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info(this.getClass().getName() + " receives:" + xml);
		
		try {
			boolean suc = false;
			List<Order> orderList = getParsedOrderList(xml);
			for (Order od : orderList) {
				logger.info(MessageFormat.format("Import order: {0} succeeded", od.getName()));
				suc = true;
			}
			if (suc) {
				setReturnCode(function, CREATE_SUCCEEDED);
				return;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		setReturnCode(function, CREATE_FAILED);

	}

	public List<Order> getParsedOrderList(String xml) throws XPathExpressionException, ParserConfigurationException, SAXException, IOException {
		DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();

		DocumentBuilder builder = domFactory.newDocumentBuilder();
		Document doc = builder.parse(new ByteArrayInputStream(xml.getBytes()));

		XPath xpath = XPathFactory.newInstance().newXPath();

//		NodeList orderNodes = (NodeList) xpath.evaluate("Z_PPFM_PCE_ORDER_CREATE/INPUT/I_ORDER_CREATE", doc, XPathConstants.NODESET);
		NodeList orderNodes = doc.getElementsByTagName("I_ORDER_CREATE");

		List<Order> orders = new ArrayList<Order>();
		for (int i = 0; i < orderNodes.getLength(); i++) {
			Node orderNode = orderNodes.item(i);
			if (orderNode == null) {
				continue;
			}
			String orderName = getNodeValue(xpath, orderNode, "ODERNR/text()");
			if (orderName == null || orderName.isEmpty()) {
				continue;
			}
			
			Line line = null;
			LineFormat lineFormat = null;

			String lineName = getNodeValue(xpath, orderNode, "RESSOURCE/text()");
			line = lineBean.findLineByName(lineName);

			if (line != null) {
				String formatName = getNodeValue(xpath, orderNode, "LAYOUT/text()");
				lineFormat = lineFormatBean.findLineFormatByName(formatName, line);
				if (lineFormat == null) {
					logger.error(MessageFormat.format("Import order: {0} failed. Lineformat: {1} does not exist on line: {2}", orderName, formatName, lineName), null);
					continue;
				}
			} else {
				logger.error(MessageFormat.format("Import order: {0} failed. Line: {1} does not exist", orderName, lineName), null);
				continue;
			}

			Order order = new Order();
			order.setName(orderName);
			order.setAutoImported(true);
			order.setCreated(new Timestamp(new Date().getTime()));
			order.setStatus((short) 1);
			order.setLineFormat(lineFormat);
			
			if (orderBean.findOrderByName(order.getName()) != null) {
				logger.error(MessageFormat.format("Import order: {0} failed. Order already exist", order.getName()), null);
				continue;
			}
			Order mergedOrder = orderBean.mergeOrder(order);
			List<OrderData> odList = new ArrayList<OrderData>();
			for (OrderdataMapping odm : OrderdataMapping.values()){

				String value = getNodeValue(xpath, orderNode, odm.name() + "/text()");
				if (value != null && !value.isEmpty()){
					AI ai = aiBean.findAiByName(odm.getAi());
					if (ai == null) {
						logger.warn(MessageFormat.format("Import order:{0} incomplete. App.ID:{1} does not exist", orderName, odm.getAi()));
						continue;
					}
					OrderData od = new OrderData();
					od.setAi(ai);
					od.setOrder(mergedOrder);
					od.setOrderID(mergedOrder.getId());
					od.setRank(ai.getFixrank() > -1 ? ai.getFixrank() : 1);
					od.setValue(value);
					odList.add(od);
				}
			}
			if (!odList.isEmpty()){
				mergedOrder.setOrderData(odList);
				orderBean.updateOrder(mergedOrder);
			}
			orders.add(mergedOrder);
		}
		return orders;
	}

}
